<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>项目解读 | ShuangChenYue</title>
    <meta name="generator" content="VuePress 1.9.9">
    <link rel="icon" href="https://cdn.jsdelivr.net/gh/cmty256/imgs-blog@main/logo/白云.38zbldnhh180.jpg">
    <meta name="description" content="满招损，谦受益">
    <meta name="keywords" content="专注于Cpp语言的旅行者">
    
    <link rel="preload" href="/assets/css/0.styles.3fffbd7d.css" as="style"><link rel="preload" href="/assets/js/app.ef25b098.js" as="script"><link rel="preload" href="/assets/js/2.4615a819.js" as="script"><link rel="preload" href="/assets/js/85.f2189c96.js" as="script"><link rel="prefetch" href="/assets/js/10.5712a6b9.js"><link rel="prefetch" href="/assets/js/11.1fed716c.js"><link rel="prefetch" href="/assets/js/12.4672093d.js"><link rel="prefetch" href="/assets/js/13.cda96393.js"><link rel="prefetch" href="/assets/js/14.0924c9b3.js"><link rel="prefetch" href="/assets/js/15.443e1f82.js"><link rel="prefetch" href="/assets/js/16.554bf912.js"><link rel="prefetch" href="/assets/js/17.994ca8e7.js"><link rel="prefetch" href="/assets/js/18.4879414d.js"><link rel="prefetch" href="/assets/js/19.f66c5ece.js"><link rel="prefetch" href="/assets/js/20.79449f9c.js"><link rel="prefetch" href="/assets/js/21.0b51ee17.js"><link rel="prefetch" href="/assets/js/22.14f9241e.js"><link rel="prefetch" href="/assets/js/23.fa858e5d.js"><link rel="prefetch" href="/assets/js/24.a420d3d2.js"><link rel="prefetch" href="/assets/js/25.fee08d36.js"><link rel="prefetch" href="/assets/js/26.92805480.js"><link rel="prefetch" href="/assets/js/27.5c60f91f.js"><link rel="prefetch" href="/assets/js/28.2bbf1597.js"><link rel="prefetch" href="/assets/js/29.05fbd423.js"><link rel="prefetch" href="/assets/js/3.7b56aee3.js"><link rel="prefetch" href="/assets/js/30.54f725db.js"><link rel="prefetch" href="/assets/js/31.3e5c530d.js"><link rel="prefetch" href="/assets/js/32.f8ecda14.js"><link rel="prefetch" href="/assets/js/33.3bef3da7.js"><link rel="prefetch" href="/assets/js/34.0e1b1990.js"><link rel="prefetch" href="/assets/js/35.21acae61.js"><link rel="prefetch" href="/assets/js/36.744eb2f7.js"><link rel="prefetch" href="/assets/js/37.077678f2.js"><link rel="prefetch" href="/assets/js/38.d2c19552.js"><link rel="prefetch" href="/assets/js/39.d873f04b.js"><link rel="prefetch" href="/assets/js/4.8844c7c6.js"><link rel="prefetch" href="/assets/js/40.a9c0394e.js"><link rel="prefetch" href="/assets/js/41.bd1b72f7.js"><link rel="prefetch" href="/assets/js/42.8c5ba50f.js"><link rel="prefetch" href="/assets/js/43.aac76280.js"><link rel="prefetch" href="/assets/js/44.2601ff73.js"><link rel="prefetch" href="/assets/js/45.2802dd41.js"><link rel="prefetch" href="/assets/js/46.3a872e80.js"><link rel="prefetch" href="/assets/js/47.fb914cfa.js"><link rel="prefetch" href="/assets/js/48.4ce4214b.js"><link rel="prefetch" href="/assets/js/49.968e0b60.js"><link rel="prefetch" href="/assets/js/5.d85ca603.js"><link rel="prefetch" href="/assets/js/50.4cee1e39.js"><link rel="prefetch" href="/assets/js/51.5cad3040.js"><link rel="prefetch" href="/assets/js/52.1612ad39.js"><link rel="prefetch" href="/assets/js/53.e9cf7aec.js"><link rel="prefetch" href="/assets/js/54.2821cc0e.js"><link rel="prefetch" href="/assets/js/55.6f8ddb85.js"><link rel="prefetch" href="/assets/js/56.58b793ba.js"><link rel="prefetch" href="/assets/js/57.3d08056f.js"><link rel="prefetch" href="/assets/js/58.880ee89f.js"><link rel="prefetch" href="/assets/js/59.987dab20.js"><link rel="prefetch" href="/assets/js/6.b5c87a76.js"><link rel="prefetch" href="/assets/js/60.6089e8d9.js"><link rel="prefetch" href="/assets/js/61.2f20e8a2.js"><link rel="prefetch" href="/assets/js/62.03592460.js"><link rel="prefetch" href="/assets/js/63.77002dd4.js"><link rel="prefetch" href="/assets/js/64.180619d0.js"><link rel="prefetch" href="/assets/js/65.2750f9b6.js"><link rel="prefetch" href="/assets/js/66.c696b1af.js"><link rel="prefetch" href="/assets/js/67.03363cd9.js"><link rel="prefetch" href="/assets/js/68.163161cc.js"><link rel="prefetch" href="/assets/js/69.6d87bcc0.js"><link rel="prefetch" href="/assets/js/7.70b0614b.js"><link rel="prefetch" href="/assets/js/70.53173d63.js"><link rel="prefetch" href="/assets/js/71.5acaf78b.js"><link rel="prefetch" href="/assets/js/72.e5473318.js"><link rel="prefetch" href="/assets/js/73.fca88a39.js"><link rel="prefetch" href="/assets/js/74.d45cfae5.js"><link rel="prefetch" href="/assets/js/75.81660c22.js"><link rel="prefetch" href="/assets/js/76.3e7aeba1.js"><link rel="prefetch" href="/assets/js/77.2e4da6e0.js"><link rel="prefetch" href="/assets/js/78.7f7d7694.js"><link rel="prefetch" href="/assets/js/79.f60ae352.js"><link rel="prefetch" href="/assets/js/8.ecc019cf.js"><link rel="prefetch" href="/assets/js/80.3a10fa1d.js"><link rel="prefetch" href="/assets/js/81.72805d9a.js"><link rel="prefetch" href="/assets/js/82.c1d3f9b6.js"><link rel="prefetch" href="/assets/js/83.9014695a.js"><link rel="prefetch" href="/assets/js/84.4602494c.js"><link rel="prefetch" href="/assets/js/86.b6a21db1.js"><link rel="prefetch" href="/assets/js/87.9be7c553.js"><link rel="prefetch" href="/assets/js/88.562483e1.js"><link rel="prefetch" href="/assets/js/89.336befe6.js"><link rel="prefetch" href="/assets/js/9.4b46b767.js"><link rel="prefetch" href="/assets/js/90.e916d603.js"><link rel="prefetch" href="/assets/js/91.873db624.js"><link rel="prefetch" href="/assets/js/92.9072026b.js"><link rel="prefetch" href="/assets/js/93.0baf9593.js"><link rel="prefetch" href="/assets/js/94.8655b40d.js"><link rel="prefetch" href="/assets/js/95.bd6a4d6c.js"><link rel="prefetch" href="/assets/js/96.943e9bb3.js"><link rel="prefetch" href="/assets/js/97.ea0c9e4a.js">
    <link rel="stylesheet" href="/assets/css/0.styles.3fffbd7d.css">
  </head>
  <body class="theme-mode-light">
    <div id="app" data-server-rendered="true"><div class="theme-container sidebar-open have-rightmenu"><header class="navbar blur"><div title="目录" class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"><img src="https://cdn.jsdelivr.net/gh/cmty256/imgs-blog@main/logo/白云.38zbldnhh180.jpg" alt="ShuangChenYue" class="logo"> <span class="site-name can-hide">ShuangChenYue</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/" class="nav-link">首页</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="CPP语言" class="dropdown-title"><!----> <span class="title" style="display:;">CPP语言</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/c5bdd8/" class="nav-link">Cpp之旅</a></li><li class="dropdown-item"><!----> <a href="/pages/279e62/" class="nav-link">Cpp专栏</a></li><li class="dropdown-item"><!----> <a href="/pages/801755/" class="nav-link">Effective_CPP</a></li><li class="dropdown-item"><!----> <a href="/pages/6b2468/" class="nav-link">muduo网络库</a></li><li class="dropdown-item"><!----> <a href="/pages/5f8c9f/" class="nav-link">Unix环境高级编程</a></li><li class="dropdown-item"><!----> <a href="/pages/3f1d21/" class="nav-link">Cpp提高编程</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="计算机基础" class="dropdown-title"><!----> <span class="title" style="display:;">计算机基础</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/7b1cb2/" class="nav-link">计算机网络</a></li><li class="dropdown-item"><!----> <a href="/pages/6048a8/" class="nav-link">操作系统</a></li><li class="dropdown-item"><!----> <a href="/pages/3b34ba/" class="nav-link">数据结构</a></li><li class="dropdown-item"><!----> <a href="/pages/412fe7/" class="nav-link">Linux</a></li><li class="dropdown-item"><!----> <a href="/pages/2dcfa1/" class="nav-link">算法</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="数据库" class="dropdown-title"><!----> <span class="title" style="display:;">数据库</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/efa3f2/" class="nav-link">基础篇</a></li><li class="dropdown-item"><!----> <a href="/pages/ccc445/" class="nav-link">MySql</a></li><li class="dropdown-item"><!----> <a href="/pages/54616e/" class="nav-link">Redis</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="系统设计" class="dropdown-title"><!----> <span class="title" style="display:;">系统设计</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/793d0a/" class="nav-link">权限校验</a></li><li class="dropdown-item"><!----> <a href="/pages/73ddd7/" class="nav-link">设计模式</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="开发日常" class="dropdown-title"><!----> <span class="title" style="display:;">开发日常</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/71f6ae/" class="nav-link">Git知识总结</a></li><li class="dropdown-item"><!----> <a href="/pages/777b8a/" class="nav-link">nvm使用小结</a></li><li class="dropdown-item"><!----> <a href="/pages/ee770e/" class="nav-link">虚拟机固定 IP 地址</a></li><li class="dropdown-item"><!----> <a href="/pages/e472d1/" class="nav-link">随笔（持续更新）</a></li><li class="dropdown-item"><!----> <a href="/pages/411aa4/" class="nav-link">VScode 插件 CodeGeeX 使用教程</a></li><li class="dropdown-item"><!----> <a href="/pages/0d525d/" class="nav-link">KylinV10 将项目上传至 Github教程</a></li><li class="dropdown-item"><!----> <a href="/pages/ef40f0/" class="nav-link">KylinV10 安装 MySQL 教程（可防踩雷）</a></li><li class="dropdown-item"><!----> <a href="/pages/f8640c/" class="nav-link">个人博客代码推送教程</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="前端学习" class="dropdown-title"><!----> <span class="title" style="display:;">前端学习</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/99897f/" class="nav-link">HTML与CSS</a></li><li class="dropdown-item"><!----> <a href="/pages/51542d/" class="nav-link">JS学习</a></li><li class="dropdown-item"><!----> <a href="/pages/803f9d/" class="nav-link">Vue3入门</a></li><li class="dropdown-item"><!----> <a href="/pages/ca4cfb/" class="nav-link">Vue3进阶</a></li><li class="dropdown-item"><!----> <a href="/pages/50e8d3/" class="nav-link">黑马Vue3</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="项目笔记" class="dropdown-title"><!----> <span class="title" style="display:;">项目笔记</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/08dfe9/" aria-current="page" class="nav-link router-link-exact-active router-link-active">ip_file_hook</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="面经" class="dropdown-title"><!----> <span class="title" style="display:;">面经</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/d69946/" class="nav-link">虎牙C++技术面经</a></li><li class="dropdown-item"><!----> <a href="/pages/29251d/" class="nav-link">金山一面复习</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="其它" class="dropdown-title"><!----> <span class="title" style="display:;">其它</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/fa256e/" class="nav-link">博客搭建</a></li><li class="dropdown-item"><!----> <a href="/pages/335531/" class="nav-link">网站收藏箱</a></li></ul></div></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <div class="sidebar-hover-trigger"></div> <aside class="sidebar" style="display:none;"><!----> <nav class="nav-links"><div class="nav-item"><a href="/" class="nav-link">首页</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="CPP语言" class="dropdown-title"><!----> <span class="title" style="display:;">CPP语言</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/c5bdd8/" class="nav-link">Cpp之旅</a></li><li class="dropdown-item"><!----> <a href="/pages/279e62/" class="nav-link">Cpp专栏</a></li><li class="dropdown-item"><!----> <a href="/pages/801755/" class="nav-link">Effective_CPP</a></li><li class="dropdown-item"><!----> <a href="/pages/6b2468/" class="nav-link">muduo网络库</a></li><li class="dropdown-item"><!----> <a href="/pages/5f8c9f/" class="nav-link">Unix环境高级编程</a></li><li class="dropdown-item"><!----> <a href="/pages/3f1d21/" class="nav-link">Cpp提高编程</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="计算机基础" class="dropdown-title"><!----> <span class="title" style="display:;">计算机基础</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/7b1cb2/" class="nav-link">计算机网络</a></li><li class="dropdown-item"><!----> <a href="/pages/6048a8/" class="nav-link">操作系统</a></li><li class="dropdown-item"><!----> <a href="/pages/3b34ba/" class="nav-link">数据结构</a></li><li class="dropdown-item"><!----> <a href="/pages/412fe7/" class="nav-link">Linux</a></li><li class="dropdown-item"><!----> <a href="/pages/2dcfa1/" class="nav-link">算法</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="数据库" class="dropdown-title"><!----> <span class="title" style="display:;">数据库</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/efa3f2/" class="nav-link">基础篇</a></li><li class="dropdown-item"><!----> <a href="/pages/ccc445/" class="nav-link">MySql</a></li><li class="dropdown-item"><!----> <a href="/pages/54616e/" class="nav-link">Redis</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="系统设计" class="dropdown-title"><!----> <span class="title" style="display:;">系统设计</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/793d0a/" class="nav-link">权限校验</a></li><li class="dropdown-item"><!----> <a href="/pages/73ddd7/" class="nav-link">设计模式</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="开发日常" class="dropdown-title"><!----> <span class="title" style="display:;">开发日常</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/71f6ae/" class="nav-link">Git知识总结</a></li><li class="dropdown-item"><!----> <a href="/pages/777b8a/" class="nav-link">nvm使用小结</a></li><li class="dropdown-item"><!----> <a href="/pages/ee770e/" class="nav-link">虚拟机固定 IP 地址</a></li><li class="dropdown-item"><!----> <a href="/pages/e472d1/" class="nav-link">随笔（持续更新）</a></li><li class="dropdown-item"><!----> <a href="/pages/411aa4/" class="nav-link">VScode 插件 CodeGeeX 使用教程</a></li><li class="dropdown-item"><!----> <a href="/pages/0d525d/" class="nav-link">KylinV10 将项目上传至 Github教程</a></li><li class="dropdown-item"><!----> <a href="/pages/ef40f0/" class="nav-link">KylinV10 安装 MySQL 教程（可防踩雷）</a></li><li class="dropdown-item"><!----> <a href="/pages/f8640c/" class="nav-link">个人博客代码推送教程</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="前端学习" class="dropdown-title"><!----> <span class="title" style="display:;">前端学习</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/99897f/" class="nav-link">HTML与CSS</a></li><li class="dropdown-item"><!----> <a href="/pages/51542d/" class="nav-link">JS学习</a></li><li class="dropdown-item"><!----> <a href="/pages/803f9d/" class="nav-link">Vue3入门</a></li><li class="dropdown-item"><!----> <a href="/pages/ca4cfb/" class="nav-link">Vue3进阶</a></li><li class="dropdown-item"><!----> <a href="/pages/50e8d3/" class="nav-link">黑马Vue3</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="项目笔记" class="dropdown-title"><!----> <span class="title" style="display:;">项目笔记</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/08dfe9/" aria-current="page" class="nav-link router-link-exact-active router-link-active">ip_file_hook</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="面经" class="dropdown-title"><!----> <span class="title" style="display:;">面经</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/d69946/" class="nav-link">虎牙C++技术面经</a></li><li class="dropdown-item"><!----> <a href="/pages/29251d/" class="nav-link">金山一面复习</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="其它" class="dropdown-title"><!----> <span class="title" style="display:;">其它</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/fa256e/" class="nav-link">博客搭建</a></li><li class="dropdown-item"><!----> <a href="/pages/335531/" class="nav-link">网站收藏箱</a></li></ul></div></div> <!----></nav>  <ul class="sidebar-links"><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>存储介质消除工具</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading open"><span>ip_file_hook</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/pages/08dfe9/" aria-current="page" class="active sidebar-link">项目解读</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level2"><a href="/pages/08dfe9/#文件访问拦截功能" class="sidebar-link">文件访问拦截功能：</a></li><li class="sidebar-sub-header level2"><a href="/pages/08dfe9/#ip-地址拦截功能" class="sidebar-link">IP 地址拦截功能：</a></li><li class="sidebar-sub-header level2"><a href="/pages/08dfe9/#inet-ntop" class="sidebar-link">inet_ntop</a></li><li class="sidebar-sub-header level2"><a href="/pages/08dfe9/#dlsym" class="sidebar-link">dlsym</a></li><li class="sidebar-sub-header level2"><a href="/pages/08dfe9/#va-start" class="sidebar-link">va_start</a></li><li class="sidebar-sub-header level2"><a href="/pages/08dfe9/#va-arg" class="sidebar-link">va_arg</a></li><li class="sidebar-sub-header level2"><a href="/pages/08dfe9/#va-end" class="sidebar-link">va_end</a></li><li class="sidebar-sub-header level2"><a href="/pages/08dfe9/#sendto" class="sidebar-link">sendto</a></li><li class="sidebar-sub-header level2"><a href="/pages/08dfe9/#realpath" class="sidebar-link">realpath</a></li><li class="sidebar-sub-header level2"><a href="/pages/08dfe9/#getpeername" class="sidebar-link">getpeername</a></li><li class="sidebar-sub-header level2"><a href="/pages/08dfe9/#inet-ntop-2" class="sidebar-link">inet_ntop</a></li><li class="sidebar-sub-header level2"><a href="/pages/08dfe9/#readlink" class="sidebar-link">readlink</a></li><li class="sidebar-sub-header level2"><a href="/pages/08dfe9/#opendir" class="sidebar-link">opendir</a></li><li class="sidebar-sub-header level2"><a href="/pages/08dfe9/#readdir" class="sidebar-link">readdir</a></li><li class="sidebar-sub-header level2"><a href="/pages/08dfe9/#atoi" class="sidebar-link">atoi</a></li></ul></li><li><a href="/pages/00e0b6/" class="sidebar-link">项目bug汇总</a></li></ul></section></li></ul> </aside> <div><main class="page"><div class="theme-vdoing-wrapper "><div class="articleInfo-wrap" data-v-06225672><div class="articleInfo" data-v-06225672><ul class="breadcrumbs" data-v-06225672><li data-v-06225672><a href="/" title="首页" class="iconfont icon-home router-link-active" data-v-06225672></a></li> <li data-v-06225672><span data-v-06225672>项目笔记</span></li><li data-v-06225672><span data-v-06225672>ip_file_hook</span></li></ul> <div class="info" data-v-06225672><div title="作者" class="author iconfont icon-touxiang" data-v-06225672><a href="javascript:;" data-v-06225672>霜晨月</a></div> <div title="创建时间" class="date iconfont icon-riqi" data-v-06225672><a href="javascript:;" data-v-06225672>2023-11-24</a></div> <!----></div></div></div> <!----> <div class="content-wrapper"><div class="right-menu-wrapper"><div class="right-menu-margin"><div class="right-menu-title">目录</div> <div class="right-menu-content"></div></div></div> <h1><img src="">项目解读<!----></h1> <!----> <div class="theme-vdoing-content content__default"><h1 id="程序流程"><a href="#程序流程" class="header-anchor">#</a> 程序流程</h1> <p>执行文件访问拦截和 IP 地址拦截的流程：</p> <h2 id="文件访问拦截功能"><a href="#文件访问拦截功能" class="header-anchor">#</a> 文件访问拦截功能：</h2> <ol><li><p>当应用程序尝试执行文件操作，例如打开文件，调用的是 <code>open</code> 或 <code>openat</code> 函数。</p></li> <li><p>由于这两个函数已经被重定向为自定义的版本，所以实际上调用的是 <code>open</code> 或 <code>openat</code> 函数的自定义替代版本。</p></li> <li><p>自定义的 <code>open</code> 或 <code>openat</code> 函数首先检查传递的文件路径和执行文件操作的进程是否符合访问控制策略。</p></li> <li><p>它检查文件路径是否在黑名单或白名单中，并检查执行文件操作的进程是否在白名单中。如果文件或进程不符合策略，函数会拒绝文件操作。</p></li> <li><p>如果文件和进程都符合策略，它会记录文件访问操作的结果，然后调用真正的 <code>open</code> 或 <code>openat</code> 函数执行操作。</p></li> <li><p>如果文件或进程不符合策略，它会记录拒绝的结果，并设置 <code>errno</code> 为 <code>EPERM</code>，表示权限被拒绝。</p></li></ol> <h2 id="ip-地址拦截功能"><a href="#ip-地址拦截功能" class="header-anchor">#</a> IP 地址拦截功能：</h2> <ol><li><p>当应用程序尝试执行网络连接操作，例如使用 <code>connect</code> 函数或发送数据到远程主机，调用的是 <code>connect</code> 或 <code>sendto</code> 函数。</p></li> <li><p>与文件访问拦截类似，这两个函数也已被重定向为自定义版本，因此实际上调用的是自定义的 <code>connect</code> 或 <code>sendto</code> 函数。</p></li> <li><p>自定义的 <code>connect</code> 或 <code>sendto</code> 函数首先检查传递的目标 IP 地址以及执行连接或数据发送操作的进程是否符合访问控制策略。</p></li> <li><p>它检查 IP 地址是否在黑名单或白名单中，并检查执行操作的进程是否在白名单中。如果 IP 地址或进程不符合策略，函数会拒绝操作。</p></li> <li><p>如果 IP 地址和进程都符合策略，它会记录 IP 操作的结果，然后调用真正的 <code>connect</code> 或 <code>sendto</code> 函数执行操作。</p></li> <li><p>如果 IP 地址或进程不符合策略，它会记录拒绝的结果，并设置 <code>errno</code> 为 <code>EPERM</code>，表示权限被拒绝。</p></li></ol> <p>总的来说，这两段代码的流程是先检查文件或 IP 地址是否符合访问控制策略，如果符合则允许操作并记录结果，如果不符合则拒绝操作并记录结果，以确保系统的安全性和遵守访问策略。</p> <h1 id="libhook-cpp"><a href="#libhook-cpp" class="header-anchor">#</a> libhook.cpp</h1> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token comment">//验证文件访问是否受到权限限制</span>
<span class="token keyword">static</span> <span class="token keyword">bool</span>
<span class="token function">allow_open</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>exe<span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>path<span class="token punctuation">,</span> string <span class="token operator">&amp;</span>return_full_path<span class="token punctuation">)</span> <span class="token keyword">noexcept</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
	<span class="token keyword">try</span>
	<span class="token punctuation">{</span>
		<span class="token comment">// 检查传入的参数是否为NULL</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span>exe <span class="token operator">==</span> <span class="token constant">NULL</span> <span class="token operator">||</span> path <span class="token operator">==</span> <span class="token constant">NULL</span><span class="token punctuation">)</span>
			<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>

		<span class="token comment">// 获取目标文件的绝对路径</span>
		<span class="token keyword">const</span> string real_absolute_path <span class="token operator">=</span> <span class="token function">get_real_path</span><span class="token punctuation">(</span><span class="token function">get_absolute_path</span><span class="token punctuation">(</span>path<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">c_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		return_full_path <span class="token operator">=</span> real_absolute_path<span class="token punctuation">;</span>

		<span class="token comment">// 遍历文件黑名单，检查是否有文件受黑名单保护</span>
		<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">auto</span> <span class="token operator">&amp;</span>i <span class="token operator">:</span> <span class="token function">file_black_list</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		<span class="token punctuation">{</span>
			<span class="token keyword">if</span> <span class="token punctuation">(</span>i<span class="token punctuation">.</span>first <span class="token operator">==</span> real_absolute_path<span class="token punctuation">)</span>
			<span class="token punctuation">{</span>
				<span class="token comment">// 文件在黑名单中，检查程序是否在黑名单</span>
				<span class="token keyword">if</span> <span class="token punctuation">(</span>i<span class="token punctuation">.</span>second<span class="token punctuation">.</span><span class="token function">count</span><span class="token punctuation">(</span>exe<span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span>
					<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
			<span class="token punctuation">}</span>
		<span class="token punctuation">}</span>

		<span class="token comment">// 遍历文件白名单，检查是否有文件受白名单保护</span>
		<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">auto</span> <span class="token operator">&amp;</span>i <span class="token operator">:</span> <span class="token function">file_white_list</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		<span class="token punctuation">{</span>
			<span class="token keyword">if</span> <span class="token punctuation">(</span>i<span class="token punctuation">.</span>first <span class="token operator">==</span> real_absolute_path<span class="token punctuation">)</span>
			<span class="token punctuation">{</span>
				<span class="token comment">// 文件在白名单中，检查程序是否不在白名单</span>
				<span class="token keyword">if</span> <span class="token punctuation">(</span>i<span class="token punctuation">.</span>second<span class="token punctuation">.</span><span class="token function">count</span><span class="token punctuation">(</span>exe<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span>
					<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
			<span class="token punctuation">}</span>
		<span class="token punctuation">}</span>
		
		<span class="token comment">// 文件访问权限通过，返回true</span>
		<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span>
	<span class="token punctuation">{</span>
		<span class="token comment">// 捕获异常，如果出现异常，也返回true</span>
		<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br></div></div><ul><li>这个函数接受两个C风格字符串（<code>exe</code> 和 <code>path</code>）以及一个字符串引用参数（<code>return_full_path</code>）。</li> <li>函数首先检查传入的<code>exe</code>和<code>path</code>是否为NULL，如果是NULL，则直接返回<code>false</code>，表示不允许访问。</li> <li>然后，它获取目标文件的绝对路径，将其保存到<code>real_absolute_path</code>变量中，并将其赋值给<code>return_full_path</code>，以便后续使用。</li> <li>函数接着遍历文件黑名单（<code>file_black_list()</code>）和文件白名单（<code>file_white_list()</code>），分别检查目标文件是否在黑名单或白名单中，以及程序是否在对应的名单中。</li> <li>如果文件在黑名单中，并且程序也在黑名单中，或者文件在白名单中，但程序不在白名单中，则返回<code>false</code>，表示不允许访问。</li> <li>最后，如果一切正常，或者在处理过程中出现异常，都会返回<code>true</code>，表示允许文件访问。</li></ul> <p>这段代码的目的是在文件访问时检查权限，以确保只有在允许名单中的程序可以访问允许名单中的文件，并且不在黑名单中。如果条件不满足，它返回<code>false</code>，表示拒绝访问。</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token comment">//验证IPv4地址的访问权限</span>
<span class="token keyword">static</span> <span class="token keyword">bool</span>
<span class="token function">allow_ipv4</span><span class="token punctuation">(</span><span class="token keyword">int</span> sockfd<span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">struct</span> <span class="token class-name">sockaddr</span> <span class="token operator">*</span>address<span class="token punctuation">,</span> socklen_t addrlen<span class="token punctuation">,</span> string <span class="token operator">&amp;</span>return_ip<span class="token punctuation">)</span> <span class="token keyword">noexcept</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
	<span class="token keyword">try</span> <span class="token punctuation">{</span>
		<span class="token keyword">char</span> buf<span class="token punctuation">[</span>INET_ADDRSTRLEN<span class="token punctuation">]</span><span class="token punctuation">;</span>
		<span class="token comment">// 强制将传入的地址指针转换为IPv4地址结构</span>
		<span class="token keyword">struct</span> <span class="token class-name">sockaddr_in</span> <span class="token operator">*</span>addr_in <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">struct</span> <span class="token class-name">sockaddr_in</span> <span class="token operator">*</span><span class="token punctuation">)</span>address<span class="token punctuation">;</span>

		<span class="token comment">// 检查地址结构长度，以及地址类型是否为IPv4</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span>addrlen <span class="token operator">&lt;</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span>sockaddr_in<span class="token punctuation">)</span> <span class="token operator">||</span>
			addr_in<span class="token operator">-&gt;</span>sin_family <span class="token operator">!=</span> AF_INET<span class="token punctuation">)</span>
			<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>

		<span class="token comment">// 将IPv4地址转换为可读的字符串形式</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">inet_ntop</span><span class="token punctuation">(</span>AF_INET<span class="token punctuation">,</span> <span class="token operator">&amp;</span>addr_in<span class="token operator">-&gt;</span>sin_addr<span class="token punctuation">,</span> buf<span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span>buf<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token constant">NULL</span><span class="token punctuation">)</span>
			<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>

		<span class="token comment">// 将IPv4地址字符串赋值给字符串变量ip</span>
		<span class="token keyword">const</span> string ip <span class="token operator">=</span> <span class="token function">string</span><span class="token punctuation">(</span>buf<span class="token punctuation">)</span><span class="token punctuation">;</span>
		return_ip <span class="token operator">=</span> ip<span class="token punctuation">;</span>

		<span class="token comment">// 获取当前进程的可执行文件路径</span>
		<span class="token keyword">const</span> string exe <span class="token operator">=</span> <span class="token function">get_real_exe_by_pid</span><span class="token punctuation">(</span><span class="token function">getpid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

		<span class="token comment">// 遍历IP地址黑名单，检查是否有IP在黑名单中</span>
		<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">auto</span> <span class="token operator">&amp;</span>i <span class="token operator">:</span> <span class="token function">ip_black_list</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		<span class="token punctuation">{</span>
			<span class="token keyword">if</span> <span class="token punctuation">(</span>i<span class="token punctuation">.</span>first <span class="token operator">==</span> ip<span class="token punctuation">)</span>
			<span class="token punctuation">{</span>
				<span class="token comment">// 如果IP在黑名单中，检查程序是否在黑名单中</span>
				<span class="token keyword">if</span> <span class="token punctuation">(</span>i<span class="token punctuation">.</span>second<span class="token punctuation">.</span><span class="token function">count</span><span class="token punctuation">(</span>exe<span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span>
					<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
			<span class="token punctuation">}</span>
		<span class="token punctuation">}</span>

		<span class="token comment">// 遍历IP地址白名单，检查是否有IP在白名单中</span>
		<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">auto</span> <span class="token operator">&amp;</span>i <span class="token operator">:</span> <span class="token function">ip_white_list</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		<span class="token punctuation">{</span>
			<span class="token keyword">if</span> <span class="token punctuation">(</span>i<span class="token punctuation">.</span>first <span class="token operator">==</span> ip<span class="token punctuation">)</span>
			<span class="token punctuation">{</span>
				<span class="token comment">// 如果IP在白名单中，检查程序是否不在白名单中</span>
				<span class="token keyword">if</span> <span class="token punctuation">(</span>i<span class="token punctuation">.</span>second<span class="token punctuation">.</span><span class="token function">count</span><span class="token punctuation">(</span>exe<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span>
					<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
			<span class="token punctuation">}</span>
		<span class="token punctuation">}</span>

		<span class="token comment">// IP地址访问权限通过，返回true</span>
		<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span>
	<span class="token punctuation">{</span>
		<span class="token comment">// 捕获异常，如果出现异常，也返回true</span>
		<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br><span class="line-number">48</span><br><span class="line-number">49</span><br><span class="line-number">50</span><br><span class="line-number">51</span><br><span class="line-number">52</span><br><span class="line-number">53</span><br><span class="line-number">54</span><br><span class="line-number">55</span><br><span class="line-number">56</span><br></div></div><div class="language- extra-class"><pre><code>// 检查地址结构长度，以及地址类型是否为IPv4
if (addrlen &lt; sizeof(sockaddr_in) || addr_in-&gt;sin_family != AF_INET)
	return true;
</code></pre></div><p>这段代码的目的是在处理套接字地址之前，确保传入的地址是有效的 IPv4 地址，并且包含足够的信息来处理，以避免内存越界错误或无效的操作。如果传入的地址不满足这些条件，函数将立即返回 <code>true</code>，表示允许访问（不进行限制）。这有助于确保代码的稳定性和安全性。</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">typedef</span> <span class="token keyword">int</span> <span class="token punctuation">(</span><span class="token operator">*</span>open_func_t<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span><span class="token punctuation">,</span> <span class="token keyword">int</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 定义一个函数指针类型，用于指向与标准 open 函数具有相同参数和返回类型的函数</span>
<span class="token keyword">int</span>
<span class="token function">open</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>path<span class="token punctuation">,</span> <span class="token keyword">int</span> flags<span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span> <span class="token comment">// 重载标准 open 函数，用于拦截文件操作</span>
<span class="token punctuation">{</span>
	<span class="token keyword">static</span> open_func_t old_open <span class="token operator">=</span> <span class="token constant">NULL</span><span class="token punctuation">;</span> <span class="token comment">// 静态函数指针，用于存储原始的 open 函数地址</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span>old_open <span class="token operator">==</span> <span class="token constant">NULL</span><span class="token punctuation">)</span> <span class="token comment">// 如果第一次调用这个函数</span>
		old_open <span class="token operator">=</span> <span class="token punctuation">(</span>open_func_t<span class="token punctuation">)</span><span class="token function">dlsym</span><span class="token punctuation">(</span>RTLD_NEXT<span class="token punctuation">,</span> <span class="token string">&quot;open&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 使用 dlsym 获取标准 open 函数的地址</span>

	mode_t mode <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token comment">// 定义文件操作的模式</span>

	<span class="token keyword">if</span> <span class="token punctuation">(</span>flags <span class="token operator">&amp;</span> O_CREAT<span class="token punctuation">)</span> <span class="token comment">// 如果传入的 flags 参数包含 O_CREAT 标志（表示在文件不存在时创建文件）</span>
	<span class="token punctuation">{</span>
		va_list args<span class="token punctuation">;</span> <span class="token comment">// 定义可变参数列表</span>
		<span class="token function">va_start</span><span class="token punctuation">(</span>args<span class="token punctuation">,</span> flags<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 初始化可变参数列表</span>
		mode <span class="token operator">=</span> <span class="token function">va_arg</span><span class="token punctuation">(</span>args<span class="token punctuation">,</span> mode_t<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 获取可变参数列表中的 mode_t 参数值</span>
		<span class="token function">va_end</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 清理可变参数列表</span>
	<span class="token punctuation">}</span>

	std<span class="token double-colon punctuation">::</span>string full_path<span class="token punctuation">;</span> <span class="token comment">// 用于存储文件的完整路径</span>

	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">allow_open</span><span class="token punctuation">(</span><span class="token function">get_real_exe_by_pid</span><span class="token punctuation">(</span><span class="token function">getpid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">c_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> path<span class="token punctuation">,</span> full_path<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// 调用 allow_open 函数检查是否允许打开文件</span>
	<span class="token punctuation">{</span>
		<span class="token function">log</span><span class="token punctuation">(</span>RESULT<span class="token double-colon punctuation">::</span>ALLOW<span class="token punctuation">,</span> TYPE<span class="token double-colon punctuation">::</span>FILE<span class="token punctuation">,</span> full_path<span class="token punctuation">,</span> <span class="token function">get_real_exe_by_pid</span><span class="token punctuation">(</span><span class="token function">getpid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">getpid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 记录允许的日志</span>
		<span class="token keyword">return</span> <span class="token function">old_open</span><span class="token punctuation">(</span>path<span class="token punctuation">,</span> flags<span class="token punctuation">,</span> mode<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 调用原始的 open 函数</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">else</span>
	<span class="token punctuation">{</span>
		<span class="token function">log</span><span class="token punctuation">(</span>RESULT<span class="token double-colon punctuation">::</span>DENY<span class="token punctuation">,</span> TYPE<span class="token double-colon punctuation">::</span>FILE<span class="token punctuation">,</span> full_path<span class="token punctuation">,</span> <span class="token function">get_real_exe_by_pid</span><span class="token punctuation">(</span><span class="token function">getpid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">getpid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 记录拒绝的日志</span>
		errno <span class="token operator">=</span> EPERM<span class="token punctuation">;</span> <span class="token comment">// 设置 errno 为 EPERM（权限错误）</span>
		<span class="token keyword">return</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span> <span class="token comment">// 返回 -1，表示打开文件失败</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>

</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br></div></div><p>这段代码是一个重载的<code>open</code>函数，它用于拦截文件操作，并在操作之前进行访问控制。以下是对这段代码的解释：</p> <ul><li><p><code>typedef int (*open_func_t)(const char *, int, ...);</code>：这行代码定义了一个函数指针类型<code>open_func_t</code>，该函数指针可以指向与标准<code>open</code>函数具有相同参数和返回类型的函数。</p></li> <li><p><code>static open_func_t old_open = NULL;</code>：这行代码定义了一个静态函数指针<code>old_open</code>，并将其初始化为<code>NULL</code>。这个指针将用于保存原始的<code>open</code>函数的地址。</p></li> <li><p><code>if (old_open == NULL)</code>：这是一个条件语句，用于检查<code>old_open</code>是否为空，如果为空，表示第一次调用这个函数。</p></li> <li><p><code>old_open = (open_func_t)dlsym(RTLD_NEXT, &quot;open&quot;);</code>：在第一次调用时，这行代码使用<code>dlsym</code>函数获取标准<code>open</code>函数的地址，并将其存储在<code>old_open</code>函数指针中。这是为了能够在拦截函数中调用原始的<code>open</code>函数。</p></li> <li><p><code>mode_t mode = 0;</code>：这行代码定义了一个<code>mode_t</code>类型的变量<code>mode</code>，并将其初始化为0。</p></li> <li><p><code>if (flags &amp; O_CREAT)</code>：这行代码检查传入的<code>flags</code>参数是否包含<code>O_CREAT</code>标志。<code>O_CREAT</code>标志表示在文件不存在时创建文件。如果<code>flags</code>包含<code>O_CREAT</code>，则进入条件块，否则跳过。</p></li> <li><p><code>va_list args; va_start(args, flags); mode = va_arg(args, mode_t); va_end(args);</code>：在包含<code>O_CREAT</code>标志的情况下，这部分代码使用可变参数列表来提取额外的参数。特别是，它使用<code>va_list</code>来存储可变参数，通过<code>va_start</code>来初始化列表，然后使用<code>va_arg</code>来获取参数的值（在这种情况下，获取了<code>mode</code>的值），最后通过<code>va_end</code>来清理列表。</p></li> <li><p><code>std::string full_path;</code>：这行代码定义了一个<code>std::string</code>类型的变量<code>full_path</code>，用于存储文件的完整路径。</p></li> <li><p><code>if (allow_open(get_real_exe_by_pid(getpid()).c_str(), path, full_path))</code>：这行代码调用<code>allow_open</code>函数来检查是否允许打开文件。它传递了三个参数：当前进程的可执行文件路径、传入的文件路径<code>path</code>，以及用于存储文件的完整路径的<code>full_path</code>。如果<code>allow_open</code>函数返回<code>true</code>，表示允许打开文件，那么它记录了一个允许的日志，并通过<code>old_open</code>调用原始的<code>open</code>函数。</p></li> <li><p><code>else</code>：如果<code>allow_open</code>函数返回<code>false</code>，表示拒绝打开文件，这行代码记录了一个拒绝的日志，并设置了<code>errno</code>为<code>EPERM</code>（表示权限错误），然后返回-1，表示打开文件失败。</p></li></ul> <p>总之，这段代码的目的是拦截标准<code>open</code>函数的调用，并在打开文件之前进行访问控制。如果满足控制条件，它将允许打开文件，并调用原始的<code>open</code>函数。如果不满足条件，它将拒绝打开文件，并返回一个错误。这有助于实施文件访问控制策略。</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">typedef</span> <span class="token keyword">int</span> <span class="token punctuation">(</span><span class="token operator">*</span>openat_func_t<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token keyword">int</span> fd<span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span><span class="token punctuation">,</span> <span class="token keyword">int</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token function">openat</span><span class="token punctuation">(</span><span class="token keyword">int</span> fd<span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>path<span class="token punctuation">,</span> <span class="token keyword">int</span> flags<span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token comment">// 定义一个指向函数指针的变量 old_openat，并初始化为 NULL</span>
    <span class="token keyword">static</span> openat_func_t old_openat <span class="token operator">=</span> <span class="token constant">NULL</span><span class="token punctuation">;</span>

    <span class="token comment">// 第一次调用时，通过 dlsym 函数获取真正的 openat 函数的地址</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>old_openat <span class="token operator">==</span> <span class="token constant">NULL</span><span class="token punctuation">)</span>
        old_openat <span class="token operator">=</span> <span class="token punctuation">(</span>openat_func_t<span class="token punctuation">)</span><span class="token function">dlsym</span><span class="token punctuation">(</span>RTLD_NEXT<span class="token punctuation">,</span> <span class="token string">&quot;openat&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// 定义文件打开权限 mode 为 0</span>
    mode_t mode <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

    <span class="token comment">// 如果 flags 包含 O_CREAT 标志，获取变长参数列表中的文件权限 mode</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>flags <span class="token operator">&amp;</span> O_CREAT<span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        va_list args<span class="token punctuation">;</span>
        <span class="token function">va_start</span><span class="token punctuation">(</span>args<span class="token punctuation">,</span> flags<span class="token punctuation">)</span><span class="token punctuation">;</span>
        mode <span class="token operator">=</span> <span class="token function">va_arg</span><span class="token punctuation">(</span>args<span class="token punctuation">,</span> mode_t<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">va_end</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    std<span class="token double-colon punctuation">::</span>string full_path<span class="token punctuation">;</span> <span class="token comment">// 用于存储实际文件的全路径</span>

    <span class="token comment">// 调用 allow_open 函数来检查文件的访问权限</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">allow_open</span><span class="token punctuation">(</span><span class="token function">get_real_exe_by_pid</span><span class="token punctuation">(</span><span class="token function">getpid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">c_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> path<span class="token punctuation">,</span> full_path<span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token comment">// 如果允许打开文件，记录相应的日志并调用真正的 openat 函数</span>
        <span class="token function">log</span><span class="token punctuation">(</span>RESULT<span class="token double-colon punctuation">::</span>ALLOW<span class="token punctuation">,</span> TYPE<span class="token double-colon punctuation">::</span>FILE<span class="token punctuation">,</span> full_path<span class="token punctuation">,</span> <span class="token function">get_real_exe_by_pid</span><span class="token punctuation">(</span><span class="token function">getpid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">getpid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token function">old_openat</span><span class="token punctuation">(</span>fd<span class="token punctuation">,</span> path<span class="token punctuation">,</span> flags<span class="token punctuation">,</span> mode<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">else</span>
    <span class="token punctuation">{</span>
        <span class="token comment">// 如果不允许打开文件，记录相应的日志，设置错误号 errno 为 EPERM，并返回 -1 表示打开失败</span>
        <span class="token function">log</span><span class="token punctuation">(</span>RESULT<span class="token double-colon punctuation">::</span>DENY<span class="token punctuation">,</span> TYPE<span class="token double-colon punctuation">::</span>FILE<span class="token punctuation">,</span> full_path<span class="token punctuation">,</span> <span class="token function">get_real_exe_by_pid</span><span class="token punctuation">(</span><span class="token function">getpid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">getpid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        errno <span class="token operator">=</span> EPERM<span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br></div></div><h1 id="tool-cpp"><a href="#tool-cpp" class="header-anchor">#</a> tool.cpp</h1> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code>string
<span class="token function">get_real_path</span> <span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>path<span class="token punctuation">)</span> <span class="token comment">// 函数名及参数说明</span>
<span class="token punctuation">{</span>
	<span class="token keyword">char</span> buf<span class="token punctuation">[</span>PATH_MAX <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// 声明一个字符数组用于存储路径</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">realpath</span> <span class="token punctuation">(</span>path<span class="token punctuation">,</span> buf<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token constant">NULL</span><span class="token punctuation">)</span> <span class="token comment">// 调用realpath函数，将传入的路径规范化为绝对路径</span>
		<span class="token keyword">return</span> path<span class="token punctuation">;</span> <span class="token comment">// 如果realpath调用失败，返回原始路径</span>
	<span class="token keyword">return</span> buf<span class="token punctuation">;</span> <span class="token comment">// 如果realpath调用成功，返回规范化后的绝对路径</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code>string <span class="token function">get_remote_ip_by_fd</span><span class="token punctuation">(</span><span class="token keyword">int</span> sockfd<span class="token punctuation">)</span> <span class="token keyword">noexcept</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">struct</span> <span class="token class-name">sockaddr_storage</span> addr<span class="token punctuation">;</span> <span class="token comment">// 声明一个套接字地址结构体，用于存储远程主机的地址信息</span>
    socklen_t addrlen <span class="token operator">=</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span>addr<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 声明并初始化地址结构体的长度变量</span>

    <span class="token comment">// 获取远程主机的地址信息并存储到 addr 结构体中，如果失败则抛出异常</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">getpeername</span><span class="token punctuation">(</span>sockfd<span class="token punctuation">,</span> <span class="token punctuation">(</span>sockaddr <span class="token operator">*</span><span class="token punctuation">)</span><span class="token operator">&amp;</span>addr<span class="token punctuation">,</span> <span class="token operator">&amp;</span>addrlen<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span>
        <span class="token keyword">throw</span> <span class="token function">SocketException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    sockaddr_in <span class="token operator">*</span>tcp_addr <span class="token operator">=</span> <span class="token punctuation">(</span>sockaddr_in <span class="token operator">*</span><span class="token punctuation">)</span><span class="token operator">&amp;</span>addr<span class="token punctuation">;</span> <span class="token comment">// 将 addr 转换为 IPv4 地址结构体</span>
    <span class="token keyword">char</span> ip<span class="token punctuation">[</span>INET_ADDRSTRLEN<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// 用于存储 IP 地址的字符数组</span>
    <span class="token comment">// 将二进制形式的 IPv4 地址转换为文本形式的 IP 地址，并存储到 ip 数组中</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">inet_ntop</span><span class="token punctuation">(</span>AF_INET<span class="token punctuation">,</span> <span class="token operator">&amp;</span>tcp_addr<span class="token operator">-&gt;</span>sin_addr<span class="token punctuation">,</span> ip<span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span>ip<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token constant">NULL</span><span class="token punctuation">)</span>
        <span class="token keyword">throw</span> <span class="token function">SocketException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> <span class="token function">string</span><span class="token punctuation">(</span>ip<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 将 IP 地址转换为 Cpp 字符串并返回</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br></div></div><div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code>string <span class="token function">get_real_exe_by_pid</span><span class="token punctuation">(</span>pid_t pid<span class="token punctuation">)</span> <span class="token comment">// 函数签名，获取指定进程的可执行文件路径</span>
<span class="token punctuation">{</span>
    string buf <span class="token operator">=</span> <span class="token function">format</span><span class="token punctuation">(</span><span class="token string">&quot;/proc/%d/exe&quot;</span><span class="token punctuation">,</span> pid<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 构造进程的符号链接路径，如 &quot;/proc/1234/exe&quot;</span>
    <span class="token keyword">char</span> exe<span class="token punctuation">[</span>PATH_MAX<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// 创建一个字符数组用于存储符号链接指向的可执行文件路径</span>
    ssize_t nread <span class="token operator">=</span> <span class="token function">readlink</span><span class="token punctuation">(</span>buf<span class="token punctuation">.</span><span class="token function">c_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> exe<span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span>exe<span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 通过 readlink 函数获取符号链接指向的路径</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>nread <span class="token operator">==</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token comment">// 如果读取失败（返回值为-1），说明可能进程不存在或者没有符号链接</span>
        <span class="token keyword">return</span> <span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 返回一个空字符串，表示获取可执行文件路径失败</span>
    exe<span class="token punctuation">[</span>nread<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token char">'\0'</span><span class="token punctuation">;</span> <span class="token comment">// 在字符数组的结尾添加 null 终止符，以确保它是一个以 null 结尾的 C 字符串</span>
    <span class="token keyword">return</span> <span class="token function">get_real_path</span><span class="token punctuation">(</span>exe<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 调用函数 get_real_path，以获取真实的路径并返回</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code>string <span class="token function">get_absolute_path</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>path<span class="token punctuation">)</span> <span class="token comment">// 函数签名，用于获取绝对路径</span>
<span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>path <span class="token operator">==</span> <span class="token constant">NULL</span> <span class="token operator">||</span> path<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token char">'/'</span><span class="token punctuation">)</span> <span class="token comment">// 如果输入路径为空或已经是绝对路径，直接返回原路径</span>
        <span class="token keyword">return</span> path<span class="token punctuation">;</span>
    <span class="token keyword">char</span> buf<span class="token punctuation">[</span>PATH_MAX <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// 创建一个字符数组用于存储当前工作目录路径</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">getcwd</span><span class="token punctuation">(</span>buf<span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span>buf<span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token constant">NULL</span><span class="token punctuation">)</span> <span class="token comment">// 通过 getcwd 函数获取当前工作目录路径</span>
        <span class="token keyword">return</span> <span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 如果获取失败，返回一个空字符串，表示无法获得绝对路径</span>
    <span class="token keyword">return</span> <span class="token function">string</span><span class="token punctuation">(</span>buf<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&quot;/&quot;</span> <span class="token operator">+</span> path<span class="token punctuation">;</span> <span class="token comment">// 构造并返回合并后的绝对路径，将当前工作目录和输入路径拼接</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code>vector<span class="token operator">&lt;</span>pid_t<span class="token operator">&gt;</span> <span class="token function">get_all_pids</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 函数签名，用于获取系统中所有的进程ID</span>
<span class="token punctuation">{</span>
    vector<span class="token operator">&lt;</span>pid_t<span class="token operator">&gt;</span> pids<span class="token punctuation">;</span> <span class="token comment">// 创建一个存储进程ID的向量</span>
    DIR <span class="token operator">*</span>p_dir <span class="token operator">=</span> <span class="token function">opendir</span><span class="token punctuation">(</span><span class="token string">&quot;/proc&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 打开位于 /proc 目录下的目录流，该目录通常包含进程信息</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>p_dir <span class="token operator">==</span> <span class="token constant">NULL</span><span class="token punctuation">)</span> <span class="token comment">// 如果目录流打开失败</span>
        <span class="token keyword">return</span> pids<span class="token punctuation">;</span> <span class="token comment">// 返回一个空向量，表示无法获取进程ID</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token punctuation">;</span><span class="token punctuation">;</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        dirent <span class="token operator">*</span>p_file <span class="token operator">=</span> <span class="token function">readdir</span><span class="token punctuation">(</span>p_dir<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 读取目录中的下一个条目</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>p_file <span class="token operator">==</span> <span class="token constant">NULL</span><span class="token punctuation">)</span> <span class="token comment">// 如果没有更多的条目可读</span>
            <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token comment">// 退出循环</span>
        pid_t pid<span class="token punctuation">;</span> <span class="token comment">// 创建一个变量用于存储进程ID</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>p_file<span class="token operator">-&gt;</span>d_type <span class="token operator">==</span> DT_DIR <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>pid <span class="token operator">=</span> <span class="token function">atoi</span><span class="token punctuation">(</span>p_file<span class="token operator">-&gt;</span>d_name<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token comment">// 如果是目录且目录名能够转换为有效的进程ID</span>
            pids<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>pid<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 将该进程ID添加到向量中</span>
    <span class="token punctuation">}</span>
    <span class="token function">closedir</span><span class="token punctuation">(</span>p_dir<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 关闭目录流，释放资源</span>
    <span class="token keyword">return</span> pids<span class="token punctuation">;</span> <span class="token comment">// 返回包含所有有效进程ID的向量</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br></div></div><h1 id="ptrace-tool-cpp"><a href="#ptrace-tool-cpp" class="header-anchor">#</a> ptrace_tool.cpp</h1> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token comment">//从目标进程的内存中读取64位整数数据（'WORD'类型）</span>
<span class="token punctuation">[</span><span class="token punctuation">[</span>deprecated<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token keyword">static</span> <span class="token keyword">void</span>
<span class="token function">get_tracee_words</span> <span class="token punctuation">(</span>pid_t pid<span class="token punctuation">,</span> WORD <span class="token operator">*</span>src<span class="token punctuation">,</span> WORD <span class="token operator">*</span>dest<span class="token punctuation">,</span> size_t len<span class="token punctuation">)</span> <span class="token keyword">noexcept</span> <span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
	<span class="token keyword">for</span> <span class="token punctuation">(</span>size_t i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> len<span class="token punctuation">;</span> <span class="token operator">++</span>i<span class="token punctuation">)</span> <span class="token punctuation">{</span>
		dest<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">ptrace</span> <span class="token punctuation">(</span>PTRACE_PEEKDATA<span class="token punctuation">,</span> pid<span class="token punctuation">,</span> src <span class="token operator">+</span> i<span class="token punctuation">,</span> <span class="token constant">NULL</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span>dest<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span>
			<span class="token keyword">throw</span> <span class="token function">PtraceException</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><ul><li>它接受参数 <code>pid</code>，要读取的数据的地址 <code>src</code>，以及存储读取数据的数组 <code>dest</code> 以及要读取的数据的长度 <code>len</code>。</li> <li>使用 <code>ptrace</code> 调用的 <code>PTRACE_PEEKDATA</code> 选项从目标进程的内存中读取数据，并将数据存储在 <code>dest</code> 数组中。</li> <li>如果读取失败，会抛出 <code>PtraceException</code> 异常。</li></ul> <blockquote><p><code>PTRACE_POKEDATA</code> 是 Linux 操作系统提供的 <code>ptrace</code> 系统调用的一个选项之一，它用于将数据写入远程进程的内存空间。这个选项通常用于修改目标进程的内存中的数据，允许一个进程追踪和修改另一个进程的执行状态和内存。</p></blockquote> <p>具体解释如下：</p> <ol><li><p><strong>ptrace 系统调用：</strong> <code>ptrace</code> 是一个用于进程追踪的系统调用，允许一个进程（通常是父进程）监视和控制另一个进程。通过 <code>ptrace</code>，一个进程可以读取和写入目标进程的寄存器、内存，以及控制目标进程的执行。</p></li> <li><p><strong>PTRACE_POKEDATA：</strong> <code>PTRACE_POKEDATA</code> 是 <code>ptrace</code> 的一个选项（请求），它表示要将数据写入目标进程的内存。这个选项通常与 <code>ptrace</code> 函数一起使用，用于修改目标进程的内存。</p></li> <li><p><strong>用途：</strong> <code>PTRACE_POKEDATA</code> 主要用于在调试或进程注入等场景中，以编程方式修改目标进程的内存数据。例如，可以使用它来修改目标进程的变量值，注入代码，或执行其他需要改变内存数据的操作。</p></li> <li><p><strong>参数：</strong> 调用 <code>ptrace</code> 时，需要提供目标进程的进程 ID，要写入的目标地址，以及要写入的数据。</p></li> <li><p><strong>注意事项：</strong> 使用 <code>PTRACE_POKEDATA</code> 需要特权，通常只能由具有足够权限的进程来执行，例如，需要具有 root 或 debug 能力的权限。</p></li></ol> <p>总之，<code>PTRACE_POKEDATA</code> 是 <code>ptrace</code> 的一个选项，用于在目标进程的内存中写入数据，通常用于调试、注入或修改目标进程的内存。</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token comment">//向目标进程的内存中写入64位整数数据</span>
<span class="token punctuation">[</span><span class="token punctuation">[</span>deprecated<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token keyword">static</span> <span class="token keyword">void</span>
<span class="token function">set_tracee_words</span> <span class="token punctuation">(</span>pid_t pid<span class="token punctuation">,</span>  WORD <span class="token operator">*</span>src<span class="token punctuation">,</span>  WORD <span class="token operator">*</span>dest<span class="token punctuation">,</span> size_t len<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
	<span class="token keyword">for</span> <span class="token punctuation">(</span>size_t i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> len<span class="token punctuation">;</span> <span class="token operator">++</span>i<span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">ptrace</span> <span class="token punctuation">(</span>PTRACE_POKEDATA<span class="token punctuation">,</span> pid<span class="token punctuation">,</span> <span class="token operator">&amp;</span>dest<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> src<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span>
			<span class="token keyword">throw</span> <span class="token function">PtraceException</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><ul><li>它接受参数 <code>pid</code>，要写入的数据 <code>src</code>，以及要写入的目标地址 <code>dest</code> 以及数据的长度 <code>len</code>。</li> <li>使用 <code>ptrace</code> 调用的 <code>PTRACE_POKEDATA</code> 选项将数据写入目标进程的内存。</li> <li>如果写入失败，会抛出 <code>PtraceException</code> 异常。</li></ul> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token comment">//计算目标进程内存中以&quot;remote_str&quot;开头的字符串的长度</span>
<span class="token keyword">int</span> <span class="token function">get_tracee_strlen</span> <span class="token punctuation">(</span>pid_t pid<span class="token punctuation">,</span> <span class="token keyword">char</span> <span class="token operator">*</span>remote_str<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
	user_regs_struct regs<span class="token punctuation">;</span>
	<span class="token keyword">int</span> len <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
	<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">;</span> <span class="token operator">++</span>i<span class="token punctuation">)</span> <span class="token punctuation">{</span>
		WORD word <span class="token operator">=</span> <span class="token function">ptrace</span> <span class="token punctuation">(</span>PTRACE_PEEKDATA<span class="token punctuation">,</span> pid<span class="token punctuation">,</span> remote_str <span class="token operator">+</span> i <span class="token operator">*</span> <span class="token keyword">sizeof</span> <span class="token punctuation">(</span>WORD<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token constant">NULL</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span>word <span class="token operator">==</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span>
			<span class="token keyword">throw</span> <span class="token function">PtraceException</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token keyword">char</span> <span class="token operator">*</span>end <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">char</span> <span class="token operator">*</span><span class="token punctuation">)</span> <span class="token function">memchr</span> <span class="token punctuation">(</span><span class="token operator">&amp;</span>word<span class="token punctuation">,</span> <span class="token char">'\0'</span><span class="token punctuation">,</span> <span class="token keyword">sizeof</span> <span class="token punctuation">(</span>word<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span>end <span class="token operator">==</span> <span class="token constant">NULL</span><span class="token punctuation">)</span>
			len <span class="token operator">+=</span> <span class="token keyword">sizeof</span> <span class="token punctuation">(</span>WORD<span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token keyword">sizeof</span> <span class="token punctuation">(</span><span class="token keyword">char</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token keyword">else</span> <span class="token punctuation">{</span>
			len <span class="token operator">+=</span> end <span class="token operator">-</span> <span class="token punctuation">(</span><span class="token keyword">char</span> <span class="token operator">*</span><span class="token punctuation">)</span> <span class="token operator">&amp;</span>word<span class="token punctuation">;</span>
			<span class="token keyword">break</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">return</span> len<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br></div></div><ul><li>它接受参数 <code>pid</code> 和 <code>remote_str</code>，表示目标进程的进程 ID 和指向目标进程内存的指针。</li> <li>通过循环逐个读取字符并查找字符串的终止符 <code>\0</code> 来计算字符串的长度。</li> <li>如果读取失败，会抛出 <code>PtraceException</code> 异常。</li></ul> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token comment">//从目标进程的内存中复制字符串并返回复制后的字符串</span>
<span class="token keyword">char</span> <span class="token operator">*</span> <span class="token function">get_tracee_strdup</span> <span class="token punctuation">(</span>pid_t pid<span class="token punctuation">,</span> <span class="token keyword">char</span> <span class="token operator">*</span>remote_str<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
	<span class="token keyword">const</span> <span class="token keyword">int</span> len <span class="token operator">=</span> <span class="token function">get_tracee_strlen</span> <span class="token punctuation">(</span>pid<span class="token punctuation">,</span> remote_str<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">char</span> buf<span class="token punctuation">[</span>len <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
	<span class="token function">get_tracee_bytes</span> <span class="token punctuation">(</span>pid<span class="token punctuation">,</span> remote_str<span class="token punctuation">,</span> buf<span class="token punctuation">,</span> len <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">return</span> <span class="token function">strdup</span> <span class="token punctuation">(</span>buf<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><ul><li>此函数用于从目标进程的内存中复制字符串并返回复制后的字符串。</li> <li>它首先调用 <code>get_tracee_strlen</code> 计算字符串的长度，然后调用 <code>get_tracee_bytes</code> 读取字符串的字节数据。</li> <li>最后，它使用 <code>strdup</code> 函数分配新的字符串并返回。</li></ul> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token comment">// 从目标进程的内存中读取字节数据</span>
<span class="token keyword">void</span> <span class="token function">get_tracee_bytes</span> <span class="token punctuation">(</span>pid_t pid<span class="token punctuation">,</span> <span class="token keyword">void</span> <span class="token operator">*</span>remote_src<span class="token punctuation">,</span> <span class="token keyword">void</span> <span class="token operator">*</span>local_dest<span class="token punctuation">,</span> size_t len<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
	<span class="token keyword">const</span> <span class="token keyword">int</span> word_len <span class="token operator">=</span> len <span class="token operator">/</span> <span class="token keyword">sizeof</span> <span class="token punctuation">(</span>WORD<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">for</span> <span class="token punctuation">(</span>size_t i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> word_len <span class="token punctuation">;</span> <span class="token operator">++</span>i<span class="token punctuation">)</span> <span class="token punctuation">{</span>
		WORD ret <span class="token operator">=</span> <span class="token function">ptrace</span> <span class="token punctuation">(</span>PTRACE_PEEKDATA<span class="token punctuation">,</span> pid<span class="token punctuation">,</span> <span class="token punctuation">(</span>WORD <span class="token operator">*</span><span class="token punctuation">)</span> remote_src <span class="token operator">+</span> i<span class="token punctuation">,</span> <span class="token constant">NULL</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span>ret <span class="token operator">==</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span>
			<span class="token keyword">throw</span> <span class="token function">PtraceException</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">(</span> <span class="token punctuation">(</span>WORD <span class="token operator">*</span><span class="token punctuation">)</span> local_dest<span class="token punctuation">)</span> <span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span>  ret<span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span>word_len <span class="token operator">&gt;</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">void</span> <span class="token operator">*</span>dest_last_word <span class="token operator">=</span> <span class="token punctuation">(</span>WORD <span class="token operator">*</span><span class="token punctuation">)</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span><span class="token keyword">char</span> <span class="token operator">*</span><span class="token punctuation">)</span> local_dest <span class="token operator">+</span> len<span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>
		<span class="token keyword">void</span> <span class="token operator">*</span>src_last_word <span class="token operator">=</span> <span class="token punctuation">(</span>WORD <span class="token operator">*</span><span class="token punctuation">)</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span><span class="token keyword">char</span> <span class="token operator">*</span><span class="token punctuation">)</span> remote_src <span class="token operator">+</span> len<span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span>len <span class="token operator">%</span> <span class="token keyword">sizeof</span> <span class="token punctuation">(</span>WORD<span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
			WORD ret <span class="token operator">=</span> <span class="token function">ptrace</span> <span class="token punctuation">(</span>PTRACE_PEEKDATA<span class="token punctuation">,</span> pid<span class="token punctuation">,</span> src_last_word<span class="token punctuation">,</span> <span class="token constant">NULL</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token keyword">if</span> <span class="token punctuation">(</span>ret <span class="token operator">==</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span>
				<span class="token keyword">throw</span> <span class="token function">PtraceException</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token operator">*</span> <span class="token punctuation">(</span>WORD <span class="token operator">*</span><span class="token punctuation">)</span> dest_last_word <span class="token operator">=</span> ret<span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br></div></div><ul><li>它接受参数 <code>pid</code>，指向目标进程内存的指针 <code>remote_src</code>，以及存储读取数据的本地缓冲区 <code>local_dest</code> 以及要读取的数据的长度 <code>len</code>。</li> <li>该函数首先将数据以 64 位整数（<code>WORD</code>）的形式逐个字的方式读取，然后将它们存储在 <code>local_dest</code> 中。</li> <li>最后，如果 <code>len</code> 不是 <code>WORD</code> 大小的整数倍，它会单独读取最后一个字。</li></ul> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token comment">// 从目标进程的内存中读取字节数据</span>
<span class="token keyword">void</span> <span class="token function">set_tracee_bytes</span> <span class="token punctuation">(</span>pid_t pid<span class="token punctuation">,</span> <span class="token keyword">void</span> <span class="token operator">*</span>remote_src<span class="token punctuation">,</span> <span class="token keyword">void</span> <span class="token operator">*</span>local_dest<span class="token punctuation">,</span> size_t len<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
	<span class="token keyword">const</span> <span class="token keyword">int</span> word_len <span class="token operator">=</span> len <span class="token operator">/</span> <span class="token keyword">sizeof</span> <span class="token punctuation">(</span>WORD<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">for</span> <span class="token punctuation">(</span>size_t i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> word_len <span class="token punctuation">;</span> <span class="token operator">++</span>i<span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">ptrace</span> <span class="token punctuation">(</span>PTRACE_POKEDATA<span class="token punctuation">,</span> pid<span class="token punctuation">,</span> <span class="token punctuation">(</span>WORD <span class="token operator">*</span><span class="token punctuation">)</span> local_dest <span class="token operator">+</span> i<span class="token punctuation">,</span> <span class="token operator">*</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span>WORD <span class="token operator">*</span><span class="token punctuation">)</span> remote_src <span class="token operator">+</span> i<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span>
			<span class="token keyword">throw</span> <span class="token function">PtraceException</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span>word_len <span class="token operator">&gt;</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">void</span> <span class="token operator">*</span>dest_last_word <span class="token operator">=</span> <span class="token punctuation">(</span>WORD <span class="token operator">*</span><span class="token punctuation">)</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span><span class="token keyword">char</span> <span class="token operator">*</span><span class="token punctuation">)</span> local_dest <span class="token operator">+</span> len<span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>
		<span class="token keyword">void</span> <span class="token operator">*</span>src_last_word <span class="token operator">=</span> <span class="token punctuation">(</span>WORD <span class="token operator">*</span><span class="token punctuation">)</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span><span class="token keyword">char</span> <span class="token operator">*</span><span class="token punctuation">)</span> remote_src <span class="token operator">+</span> len<span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span>len <span class="token operator">%</span> <span class="token keyword">sizeof</span> <span class="token punctuation">(</span>WORD<span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
			<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">ptrace</span> <span class="token punctuation">(</span>PTRACE_POKEDATA<span class="token punctuation">,</span> pid<span class="token punctuation">,</span>  dest_last_word<span class="token punctuation">,</span> <span class="token operator">*</span> <span class="token punctuation">(</span>WORD <span class="token operator">*</span><span class="token punctuation">)</span> src_last_word<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span>
				<span class="token keyword">throw</span> <span class="token function">PtraceException</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br></div></div><p>它的参数和操作方式与 <code>get_tracee_bytes</code> 函数类似，但是它用 <code>ptrace</code> 调用的 <code>PTRACE_POKEDATA</code> 选项将数据写入目标进程的内存。</p> <h1 id="总结"><a href="#总结" class="header-anchor">#</a> 总结：</h1> <h2 id="inet-ntop"><a href="#inet-ntop" class="header-anchor">#</a> inet_ntop</h2> <p><code>inet_ntop</code> 函数用于将二进制形式的网络地址转换为人类可读的IPv4或IPv6地址表示。</p> <p>其原型如下：</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span><span class="token function">inet_ntop</span><span class="token punctuation">(</span><span class="token keyword">int</span> af<span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">void</span> <span class="token operator">*</span>src<span class="token punctuation">,</span> <span class="token keyword">char</span> <span class="token operator">*</span>dst<span class="token punctuation">,</span> socklen_t size<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><ul><li><code>af</code>：地址族（Address Family），可以是 <code>AF_INET</code>（IPv4）或 <code>AF_INET6</code>（IPv6）。</li> <li><code>src</code>：指向要转换的二进制网络地址的指针。</li> <li><code>dst</code>：指向用于存储结果的缓冲区。</li> <li><code>size</code>：<code>dst</code> 缓冲区的大小。</li></ul> <p><code>inet_ntop</code> 函数的原理是将二进制网络地址转换为可读的点分十进制（IPv4）或冒号十六进制（IPv6）表示。函数根据给定的地址族 <code>af</code>，采用不同的格式化方式来完成这一转换。</p> <p>对于 IPv4 地址（<code>af</code> 为 <code>AF_INET</code>），<code>inet_ntop</code> 函数将 32 位的二进制地址拆分成四个 8 位的部分，然后将它们以点分十进制的形式表示。例如，二进制地址 <code>0x7F000001</code> 被转换为字符串 &quot;127.0.0.1&quot;。</p> <p>对于 IPv6 地址（<code>af</code> 为 <code>AF_INET6</code>），<code>inet_ntop</code> 函数将 128 位的二进制地址按照冒号十六进制表示。例如，IPv6 地址 <code>2001:0db8:85a3:0000:0000:8a2e:0370:7334</code> 保持不变。</p> <h2 id="dlsym"><a href="#dlsym" class="header-anchor">#</a> dlsym</h2> <p><code>dlsym</code> 函数是动态链接库操作的一部分，用于在共享库中查找符号（函数或变量）。其原型如下：</p> <div class="language-c line-numbers-mode"><pre class="language-c"><code><span class="token keyword">void</span> <span class="token operator">*</span><span class="token function">dlsym</span><span class="token punctuation">(</span><span class="token keyword">void</span> <span class="token operator">*</span>handle<span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>symbol<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><ul><li><code>handle</code>：表示已经打开的动态链接库的句柄，通常是由 <code>dlopen</code> 函数返回的。</li> <li><code>symbol</code>：是你想查找的符号（函数或变量）的名称。</li></ul> <p><code>dlsym</code> 函数的工作原理涉及以下几个步骤：</p> <ol><li><code>dlsym</code> 函数通过 <code>handle</code> 参数确定要在哪个已加载的共享库中查找符号。</li> <li>它会在给定的共享库中查找具有名称 <code>symbol</code> 的符号。</li> <li>如果找到符号，<code>dlsym</code> 返回指向该符号的指针（函数指针或变量指针）；否则，返回 <code>NULL</code>。</li></ol> <p>这个函数的主要用途是在运行时从共享库中获取函数或变量的地址，以便在程序中调用或使用它们。这是一种动态加载共享库中的函数的方法，可以在程序运行时决定使用哪个共享库，并且可以根据需要加载或卸载这些库。</p> <h2 id="va-start"><a href="#va-start" class="header-anchor">#</a> va_start</h2> <p><code>va_start</code> 函数是 C/Cpp 标准库中的一个宏，用于在函数内部访问可变参数列表（variable argument list）。它的原型通常定义在 <code>&lt;cstdarg&gt;</code> 或 <code>&lt;stdarg.h&gt;</code> 头文件中，但是 <code>va_start</code> 宏的具体实现会根据编译器和平台而有所不同。</p> <p><code>va_start</code> 宏的一般原型如下：</p> <div class="language-c line-numbers-mode"><pre class="language-c"><code><span class="token keyword">void</span> <span class="token function">va_start</span><span class="token punctuation">(</span>va_list ap<span class="token punctuation">,</span> last_arg<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><ul><li><code>va_list ap</code> 是一个指向可变参数列表的指针，它将在函数内部用于迭代访问参数。</li> <li><code>last_arg</code> 是可变参数列表中的最后一个固定参数，用于确定可变参数列表的起始位置。</li></ul> <p><code>va_start</code> 宏的原理是基于编译器和体系结构的底层机制，通常使用汇编代码来实现。它的主要任务是将 <code>va_list</code> 指针初始化为指向参数列表中的第一个可变参数。</p> <p>具体实现方法取决于编译器和平台，但通常涉及以下步骤：</p> <ol><li><p>确定固定参数的位置。编译器需要知道在参数列表中哪里是可变参数的开始位置。这通常由 <code>last_arg</code> 参数指定。</p></li> <li><p>计算可变参数列表的地址。编译器会使用一些规则来计算可变参数列表的地址。这通常涉及堆栈指针（栈帧指针）的调整和偏移计算。</p></li> <li><p>初始化 <code>va_list</code> 指针。<code>va_start</code> 宏会将 <code>va_list</code> 指针初始化为可变参数列表的起始位置，以便函数内部可以使用 <code>va_arg</code> 宏来访问参数。</p></li></ol> <p>总之，<code>va_start</code> 宏的原理是在函数内部为可变参数列表创建一个指针，使得程序可以依次访问参数。不同编译器和平台的实现可能会有所不同，但通常都是基于底层的堆栈和内存管理机制。</p> <h2 id="va-arg"><a href="#va-arg" class="header-anchor">#</a> va_arg</h2> <p><code>va_arg</code> 函数是 C/Cpp 标准库中用于访问可变参数列表（variable argument list）的宏。它的原型通常定义在 <code>&lt;cstdarg&gt;</code> 或 <code>&lt;stdarg.h&gt;</code> 头文件中，但 <code>va_arg</code> 宏的具体实现会根据编译器和平台而有所不同。</p> <p>一般情况下，<code>va_arg</code> 宏的原型如下：</p> <div class="language-c line-numbers-mode"><pre class="language-c"><code>type <span class="token function">va_arg</span><span class="token punctuation">(</span>va_list ap<span class="token punctuation">,</span> type<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><ul><li><code>va_list ap</code> 是一个指向可变参数列表的指针，它在 <code>va_start</code> 函数之后初始化，用于迭代访问参数。</li> <li><code>type</code> 是要获取的参数的类型。</li></ul> <p><code>va_arg</code> 宏的原理是基于编译器和体系结构的底层机制，通常使用汇编代码来实现。它的主要任务是从可变参数列表中按指定类型提取参数的值。</p> <p>具体实现方法取决于编译器和平台，但通常涉及以下步骤：</p> <ol><li><p>计算参数的大小。编译器需要知道参数的大小，以便正确地从堆栈中读取数据。这取决于参数的类型。</p></li> <li><p>更新 <code>va_list</code> 指针。<code>va_arg</code> 宏会将 <code>va_list</code> 指针移动到下一个参数的位置，以准备下一次调用 <code>va_arg</code>。</p></li> <li><p>从内存中读取参数值。<code>va_arg</code> 宏通过 <code>va_list</code> 指针获取参数的值，然后将指针移动到下一个参数的位置。</p></li></ol> <p>总之，<code>va_arg</code> 宏的原理是在可变参数列表中按照指定的类型提取参数值。不同编译器和平台的实现可能会有所不同，但通常都是基于底层的堆栈和内存管理机制。 <code>va_arg</code> 宏为处理可变参数提供了一种通用的方法，使得在不知道参数个数和类型的情况下能够访问参数。</p> <h2 id="va-end"><a href="#va-end" class="header-anchor">#</a> va_end</h2> <p><code>va_end</code> 函数是 C/Cpp 标准库中用于终止可变参数列表（variable argument list）操作的宏。它的原型通常定义在 <code>&lt;cstdarg&gt;</code> 或 <code>&lt;stdarg.h&gt;</code> 头文件中，但 <code>va_end</code> 宏的具体实现会根据编译器和平台而有所不同。</p> <p>一般情况下，<code>va_end</code> 宏的原型如下：</p> <div class="language-c line-numbers-mode"><pre class="language-c"><code><span class="token keyword">void</span> <span class="token function">va_end</span><span class="token punctuation">(</span>va_list ap<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><ul><li><code>va_list ap</code> 是一个指向可变参数列表的指针，它在 <code>va_start</code> 函数之后初始化。</li></ul> <p><code>va_end</code> 宏的原理是用于清理 <code>va_list</code> 指针，以便资源得到正确释放。具体实现方法取决于编译器和平台，但通常会在 <code>va_end</code> 中执行以下操作：</p> <ol><li><p>将 <code>va_list</code> 指针设置为一个未定义或无效的状态。这意味着该指针不再指向可变参数列表中的任何参数。</p></li> <li><p>释放或清理 <code>va_list</code> 指针可能使用的任何资源。这通常涉及一些与堆栈或寄存器状态相关的操作，以确保不会出现内存泄漏或资源泄漏。</p></li></ol> <p>总之，<code>va_end</code> 宏的原理是用于清理和终止可变参数列表的操作，以确保不会出现资源泄漏或其他问题。不同编译器和平台的实现方式可能有所不同，但它们的共同目标是安全地结束可变参数列表的操作。</p> <h2 id="sendto"><a href="#sendto" class="header-anchor">#</a> sendto</h2> <p><code>sendto</code> 函数是用于将数据发送到指定的目标地址的系统调用，通常用于网络编程。它的原型如下：</p> <div class="language-c line-numbers-mode"><pre class="language-c"><code><span class="token class-name">ssize_t</span> <span class="token function">sendto</span><span class="token punctuation">(</span><span class="token keyword">int</span> sockfd<span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">void</span> <span class="token operator">*</span>buf<span class="token punctuation">,</span> <span class="token class-name">size_t</span> len<span class="token punctuation">,</span> <span class="token keyword">int</span> flags<span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">struct</span> <span class="token class-name">sockaddr</span> <span class="token operator">*</span>dest_addr<span class="token punctuation">,</span> <span class="token class-name">socklen_t</span> addrlen<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><ul><li><code>sockfd</code> 是套接字文件描述符，用于标识要发送数据的套接字。</li> <li><code>buf</code> 是包含要发送的数据的缓冲区。</li> <li><code>len</code> 是要发送的数据的字节数。</li> <li><code>flags</code> 是发送选项，通常可以设置为 0。</li> <li><code>dest_addr</code> 是目标地址的指针，通常是 <code>struct sockaddr</code> 结构的指针，包含目标地址信息。</li> <li><code>addrlen</code> 是目标地址结构的长度。</li></ul> <p><code>sendto</code> 函数的原理是将 <code>buf</code> 中的数据发送到指定的目标地址，然后返回发送的字节数。数据包将通过 <code>sockfd</code> 套接字发送，而 <code>dest_addr</code> 和 <code>addrlen</code> 用于指定目标地址。</p> <p>原理包括以下步骤：</p> <ol><li>根据 <code>sockfd</code> 找到关联的套接字，该套接字用于数据发送。</li> <li>将 <code>buf</code> 缓冲区中的数据封装成数据包，同时添加目标地址信息（由 <code>dest_addr</code> 指定）。</li> <li>数据包被发送到目标地址，这通常涉及到网络协议栈的操作。</li> <li><code>sendto</code> 函数返回发送的字节数或出现的错误。</li></ol> <p><code>sendto</code> 可以用于 UDP 和基于 IP 的协议（例如 ICMP），以便将数据发送到指定的目标地址。通过 <code>dest_addr</code> 参数，您可以指定数据包要发送到的目标主机和端口。此函数常用于网络编程中，用于实现数据的发送和接收。</p> <h2 id="realpath"><a href="#realpath" class="header-anchor">#</a> realpath</h2> <p><code>realpath</code> 函数用于获取一个路径的绝对路径，将相对路径转换为绝对路径。其原型如下：</p> <div class="language-c line-numbers-mode"><pre class="language-c"><code><span class="token keyword">char</span> <span class="token operator">*</span><span class="token function">realpath</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>path<span class="token punctuation">,</span> <span class="token keyword">char</span> <span class="token operator">*</span>resolved_path<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><ul><li><code>path</code> 是要获取绝对路径的输入路径。</li> <li><code>resolved_path</code> 是一个缓冲区，用于存储解析后的绝对路径。它可以为 <code>NULL</code>，如果为 <code>NULL</code>，<code>realpath</code> 函数会自动为您分配内存。</li></ul> <p><code>realpath</code> 函数的原理是将输入的相对路径 <code>path</code> 转换为绝对路径并存储在 <code>resolved_path</code> 缓冲区中。如果 <code>resolved_path</code> 参数为 <code>NULL</code>，则会自动分配内存并存储绝对路径。</p> <p>原理包括以下步骤：</p> <ol><li><code>realpath</code> 检查输入路径 <code>path</code> 是否为相对路径或绝对路径。如果 <code>path</code> 为绝对路径（以 <code>/</code> 开头），则它是其自身的绝对路径，无需进一步处理。</li> <li>如果 <code>path</code> 为相对路径，<code>realpath</code> 将获取当前工作目录，并将其与 <code>path</code> 连接，以得到绝对路径。</li> <li><code>realpath</code> 对路径中的符号链接进行解析，以获得路径的最终绝对路径。这包括将路径中的 <code>.</code> 和 <code>..</code> 等符号链接替换为实际目录。</li> <li>最终的绝对路径存储在 <code>resolved_path</code> 缓冲区中，或者如果 <code>resolved_path</code> 为 <code>NULL</code>，则由 <code>realpath</code> 函数自动分配内存来存储绝对路径。</li> <li><code>realpath</code> 返回指向 <code>resolved_path</code> 缓冲区的指针，其中包含了输入路径的绝对路径。这个缓冲区可以被后续代码使用。</li></ol> <p><code>realpath</code> 函数通常用于获取文件的绝对路径，以确保以绝对路径方式引用文件。这在文件系统操作和路径处理中非常有用，可以避免相对路径引发的问题。</p> <h2 id="getpeername"><a href="#getpeername" class="header-anchor">#</a> getpeername</h2> <p><code>getpeername</code> 函数用于获取与已连接套接字关联的远程端的地址信息。其原型如下：</p> <div class="language-c line-numbers-mode"><pre class="language-c"><code><span class="token keyword">int</span> <span class="token function">getpeername</span><span class="token punctuation">(</span><span class="token keyword">int</span> sockfd<span class="token punctuation">,</span> <span class="token keyword">struct</span> <span class="token class-name">sockaddr</span> <span class="token operator">*</span>addr<span class="token punctuation">,</span> <span class="token class-name">socklen_t</span> <span class="token operator">*</span>addrlen<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><ul><li><code>sockfd</code> 是一个已连接套接字的文件描述符，用于表示与远程主机建立的连接。</li> <li><code>addr</code> 是一个指向 <code>struct sockaddr</code> 结构的指针，用于存储远程端的地址信息。</li> <li><code>addrlen</code> 是一个指向 <code>socklen_t</code> 类型的指针，用于存储 <code>addr</code> 缓冲区的长度。</li></ul> <p><code>getpeername</code> 函数的原理是在套接字 <code>sockfd</code> 上执行操作，以获取远程端的地址信息并存储在 <code>addr</code> 缓冲区中。</p> <p>原理包括以下步骤：</p> <ol><li><code>getpeername</code> 函数接收 <code>sockfd</code>，这是一个已连接套接字，表示与远程主机的连接。</li> <li>它将 <code>addr</code> 缓冲区用于存储远程端的地址信息。</li> <li>通过 <code>addrlen</code> 参数传递缓冲区的大小。</li> <li><code>getpeername</code> 函数将远程端的地址信息填充到 <code>addr</code> 缓冲区中。</li> <li>如果成功，函数返回0，否则返回-1，并在错误情况下设置 <code>errno</code>，以指示错误的类型。</li></ol> <p><code>getpeername</code> 函数通常用于网络编程，以获取远程客户端的地址信息，以便了解与服务器建立连接的客户端。这是在服务器端套接字编程中的常见用例，用于识别连接到服务器的客户端的地址信息。</p> <h2 id="inet-ntop-2"><a href="#inet-ntop-2" class="header-anchor">#</a> inet_ntop</h2> <p><code>inet_ntop</code> 函数用于将网络字节序的 IP 地址转换为人类可读的 IP 地址字符串。其原型如下：</p> <div class="language-c line-numbers-mode"><pre class="language-c"><code><span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span><span class="token function">inet_ntop</span><span class="token punctuation">(</span><span class="token keyword">int</span> af<span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">void</span> <span class="token operator">*</span>src<span class="token punctuation">,</span> <span class="token keyword">char</span> <span class="token operator">*</span>dst<span class="token punctuation">,</span> <span class="token class-name">socklen_t</span> size<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><ul><li><code>af</code> 是地址族参数，通常是 <code>AF_INET</code> 表示 IPv4 地址族或 <code>AF_INET6</code> 表示 IPv6 地址族。</li> <li><code>src</code> 是指向包含二进制 IP 地址的内存地址。</li> <li><code>dst</code> 是用于存储 IP 地址字符串的缓冲区。</li> <li><code>size</code> 是 <code>dst</code> 缓冲区的大小。</li></ul> <p>原理：
<code>inet_ntop</code> 函数的实现依赖于不同的操作系统，但其核心思想相似。它将二进制 IP 地址转换为字符串的过程通常如下：</p> <ol><li><p>首先，函数根据地址族 (<code>af</code>) 来判断是 IPv4 还是 IPv6 地址。</p></li> <li><p>然后，它根据地址族决定如何将二进制地址解析成字符串。对于 IPv4 地址，将四个 8 位整数以点分隔的形式拼接成字符串；对于 IPv6 地址，将 16 位整数以冒号分隔的形式拼接成字符串。</p></li> <li><p>函数将转换后的字符串复制到 <code>dst</code> 缓冲区中，同时确保不会超过 <code>size</code> 字节的长度。</p></li> <li><p>如果转换成功，函数返回指向 <code>dst</code> 缓冲区的指针，否则返回 <code>NULL</code>，并在 <code>errno</code> 中设置相应的错误码，如 <code>EINVAL</code>（无效的地址族）或 <code>ENOSPC</code>（缓冲区不足）。</p></li></ol> <p>需要注意的是，<code>inet_ntop</code> 是将二进制地址转换为可读字符串的逆过程，与之相反的函数是 <code>inet_pton</code>，它将字符串转换为二进制地址。这两个函数在网络编程中用于进行 IP 地址的解析和构建。</p> <h2 id="readlink"><a href="#readlink" class="header-anchor">#</a> readlink</h2> <p><code>readlink</code> 函数用于读取符号链接的目标路径。它的原型如下：</p> <div class="language-c line-numbers-mode"><pre class="language-c"><code><span class="token class-name">ssize_t</span> <span class="token function">readlink</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>path<span class="token punctuation">,</span> <span class="token keyword">char</span> <span class="token operator">*</span>buf<span class="token punctuation">,</span> <span class="token class-name">size_t</span> bufsiz<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><ul><li><code>path</code> 是要读取的符号链接文件的路径。</li> <li><code>buf</code> 是一个字符数组，用于存储目标路径。</li> <li><code>bufsiz</code> 是 <code>buf</code> 的大小，用于指定目标路径的最大长度。</li></ul> <p>原理：
<code>readlink</code> 函数的目的是获取符号链接文件所指向的实际目标路径。其工作原理如下：</p> <ol><li><p>当调用 <code>readlink</code> 函数时，它会打开 <code>path</code> 所指定的符号链接文件，并尝试读取链接文件的内容。</p></li> <li><p>如果成功，它将读取的内容存储在 <code>buf</code> 中，并返回所复制的字符数，不包括 null 终止字符。如果 <code>bufsiz</code> 大于实际目标路径的长度，<code>buf</code> 中的数据将以 null 终止。</p></li> <li><p>如果读取的内容超过了 <code>buf</code> 的容量（<code>bufsiz</code> 不足以容纳目标路径），<code>readlink</code> 函数会截断目标路径并返回截断后的字符数。此时，<code>buf</code> 中的数据仍以 null 终止。</p></li> <li><p>如果读取符号链接文件失败，<code>readlink</code> 函数返回 -1，并在 <code>errno</code> 中设置相应的错误码，如 <code>EACCES</code>（权限不足）或 <code>ENOENT</code>（文件不存在）。</p></li></ol> <p>需要注意的是，<code>readlink</code> 仅适用于符号链接文件。对于硬链接或普通文件，它不起作用。符号链接是一种特殊类型的文件，其中包含对其他文件或目录的路径引用，因此读取它的内容通常是获取所引用文件的路径。</p> <h2 id="opendir"><a href="#opendir" class="header-anchor">#</a> opendir</h2> <p><code>opendir</code> 函数用于打开指定目录并返回一个指向目录流（<code>DIR</code> 结构体的指针）的句柄，以便后续对目录中的文件和子目录进行遍历。其原型如下：</p> <div class="language-c line-numbers-mode"><pre class="language-c"><code>DIR <span class="token operator">*</span><span class="token function">opendir</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>dirname<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><ul><li><code>dirname</code> 是一个字符串，表示要打开的目录的路径名。</li></ul> <p>原理：</p> <ol><li><p>当调用 <code>opendir</code> 函数时，它会尝试打开指定路径的目录。</p></li> <li><p>如果成功，<code>opendir</code> 返回一个指向 <code>DIR</code> 结构体的指针，该结构体用于表示打开的目录流。这个结构体包含有关目录的信息，如目录的文件描述符和目录项列表。</p></li> <li><p>目录流句柄可以用于后续的目录遍历操作，例如使用 <code>readdir</code> 函数读取目录中的文件和子目录项。</p></li> <li><p>如果打开目录失败，<code>opendir</code> 返回 <code>NULL</code>，表示出现了错误。在这种情况下，通常可以使用 <code>errno</code> 来获取出错的详细信息，例如 <code>ENOENT</code> 表示指定的目录不存在，<code>EACCES</code> 表示无权限访问目录等。</p></li></ol> <p><code>opendir</code> 和 <code>readdir</code> 函数通常用于目录遍历操作，允许程序在目录中查找文件和子目录，并对它们进行处理。这对于编写文件管理和操作系统相关的程序非常有用。</p> <h2 id="readdir"><a href="#readdir" class="header-anchor">#</a> readdir</h2> <p><code>readdir</code> 函数用于从已打开的目录流中读取下一个目录项。其原型如下：</p> <div class="language-c line-numbers-mode"><pre class="language-c"><code><span class="token keyword">struct</span> <span class="token class-name">dirent</span> <span class="token operator">*</span><span class="token function">readdir</span><span class="token punctuation">(</span>DIR <span class="token operator">*</span>dirp<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><ul><li><p><code>dirp</code> 是一个指向已打开目录流（<code>DIR</code> 结构体的指针）的句柄。</p></li> <li><p><code>struct dirent</code> 是一个结构体，表示目录中的一个项，包括文件名、文件类型和其他属性。</p></li></ul> <p>原理：</p> <ol><li><p><code>readdir</code> 函数从指定的目录流 <code>dirp</code> 中读取下一个目录项，并返回一个指向 <code>struct dirent</code> 结构体的指针，其中包含有关该目录项的信息。</p></li> <li><p>如果目录流已经到达末尾（即没有更多的目录项可读取），或者出现错误，<code>readdir</code> 返回 <code>NULL</code>，表示读取结束或出现错误。此时，通常可以使用 <code>errno</code> 来获取出错的详细信息。</p></li> <li><p>通过多次调用 <code>readdir</code> 函数，可以依次读取目录中的所有文件和子目录项，直到读取到末尾为止。</p></li> <li><p><code>struct dirent</code> 结构体中包含了目录项的信息，如文件名、文件类型和其他属性。您可以使用这些信息来进一步处理目录中的文件和子目录。</p></li></ol> <p><code>readdir</code> 函数通常与 <code>opendir</code> 函数一起使用，用于在目录中遍历文件和子目录。这对于需要执行文件管理或目录操作的应用程序非常有用。</p> <h2 id="atoi"><a href="#atoi" class="header-anchor">#</a> atoi</h2> <p><code>atoi</code> 函数用于将字符串转换为整数（<code>int</code>）。其原型如下：</p> <div class="language-c line-numbers-mode"><pre class="language-c"><code><span class="token keyword">int</span> <span class="token function">atoi</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>str<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><ul><li><code>str</code> 是一个指向包含表示整数的字符串的指针。</li></ul> <p>原理：</p> <ol><li><p><code>atoi</code> 函数从字符串 <code>str</code> 的起始位置开始扫描，并跳过前导空白字符（如空格、制表符等）。</p></li> <li><p>一旦遇到非空白字符，<code>atoi</code> 将开始解析整数。它会继续读取字符，直到遇到非数字字符或字符串的末尾。</p></li> <li><p>解析期间，<code>atoi</code> 将读取的字符转换为整数，并将其积累到一个整数值中。该整数值的初始值为零。</p></li> <li><p>如果字符串中包含无效字符或字符串为空，<code>atoi</code> 将停止解析，并返回当前积累的整数值。</p></li> <li><p>如果整数超出了 <code>int</code> 数据类型的范围，结果是未定义的。</p></li> <li><p>返回值为解析后的整数值。</p></li></ol> <p><code>atoi</code> 主要用于将字符串形式的数字转换为整数，常用于文本处理和输入转换，但不提供错误检测机制。如果需要更强大的字符串到整数的转换和错误处理，可以使用 <code>strtol</code> 函数或其他更安全的替代方法。</p></div></div> <!----> <div class="page-edit"><!----> <!----> <!----></div> <div class="page-nav-wapper"><div class="page-nav-centre-wrap"><a href="/pages/67c5c8/" class="page-nav-centre page-nav-centre-prev"><div class="tooltip">项目笔记</div></a> <a href="/pages/00e0b6/" class="page-nav-centre page-nav-centre-next"><div class="tooltip">项目bug汇总</div></a></div> <div class="page-nav"><p class="inner"><span class="prev">
        ←
        <a href="/pages/67c5c8/" class="prev">项目笔记</a></span> <span class="next"><a href="/pages/00e0b6/">项目bug汇总</a>→
      </span></p></div></div></div> <!----></main></div> <div class="footer"><!----> 
  Theme by
  <a href="https://github.com/xugaoyi/vuepress-theme-vdoing" target="_blank" title="本站主题">Vdoing</a> 
    | Copyright © 2023-2023
    <span>霜晨月</span></div> <div class="buttons"><div title="返回顶部" class="button blur go-to-top iconfont icon-fanhuidingbu" style="display:none;"></div> <div title="去评论" class="button blur go-to-comment iconfont icon-pinglun" style="display:none;"></div> <div title="主题模式" class="button blur theme-mode-but iconfont icon-zhuti"><ul class="select-box" style="display:none;"><li class="iconfont icon-zidong">
          跟随系统
        </li><li class="iconfont icon-rijianmoshi">
          浅色模式
        </li><li class="iconfont icon-yejianmoshi">
          深色模式
        </li><li class="iconfont icon-yuedu">
          阅读模式
        </li></ul></div></div> <!----> <!----> <!----></div><div class="global-ui"><canvas id="vuepress-canvas-cursor"></canvas></div></div>
    <script src="/assets/js/app.ef25b098.js" defer></script><script src="/assets/js/2.4615a819.js" defer></script><script src="/assets/js/85.f2189c96.js" defer></script>
  </body>
</html>
